#include <QObject>
#include <QList>
#include <QIcon>
#include <QTimer>
#include <QContactThumbnail>
#include <QContact>

#include "contactloadthread.h"
#include "logdb.h"
#include "dbrecord.h"
#include "dbrecords.h"
#include "settings.h"
#include "cacheitem.h"

#include <QDebug>
#include <QTime>

QTM_USE_NAMESPACE

DBRecords::DBRecords( OptionsClass::FilterOptions filterOptions, int maxRecords, QObject * parent ):
	 QObject( parent ), m_filterOptions( filterOptions ),  m_maxRecords( maxRecords ), m_thread( 0 )
{
	m_ldb = new LogDB( parent );
	connect( this, SIGNAL( contactRequested( int ) ), this, SLOT( processContactRequest( int ) ) );
}

DBRecords::~DBRecords()
{
	clear();
//	m_db.close();
	m_ldb->disconnectDB();
	if ( m_thread )
	{
		m_thread->terminate();
	}
}

void DBRecords::clear()
{
	while ( ! m_dbRecs.empty() )
		delete m_dbRecs.takeFirst();

	while ( ! m_contactCache.empty() )
		delete m_contactCache.takeFirst();

	m_dbRecs.clear();
	m_contactCache.clear();
	m_threadQueue.clear();
}

void DBRecords::setMaxRecords( int m )
{
	CacheItem *ci;
	DBRecord *dr;

	if ( m < m_maxRecords )
	{
		for ( int i = m_maxRecords - 1; i > m - 1; i--  )
		{
			for ( int j = 0; j < m_contactCache.count(); j++ )
			{
				if ( m_contactCache.at( j )->id() == m_dbRecs.at( i )->id() )
				{
					ci = m_contactCache.at( j );
					m_contactCache.removeAt( j );
					delete ci;
					break;
				}
			}
			for ( int j = 0; j < m_threadQueue.count(); j++ )
			{
				if ( m_threadQueue.at( j ) == m_dbRecs.at( i )->id() ) {
					m_threadQueue.removeAt( j );
					break;
				}
			}
			dr = m_dbRecs.at( i );
			m_dbRecs.removeAt( i );
			delete dr;
		}
		m_maxRecords = m;
		emit variableChanged();
		emit loaded();
	}
	else if ( m > m_maxRecords )
	{
		m_maxRecords = m;
		emit variableChanged();
		load();
	}
}

void DBRecords::setFilterOptions( OptionsClass::FilterOptions f )
{
	m_filterOptions = f;
	emit variableChanged();
	load();
}

void DBRecords::setEventFilter( OptionsClass::FilterOptions f )
{
	// clear stored event flags with DirectionMask
	m_filterOptions = f | ( m_filterOptions & OptionsClass::DirectionMask );
	emit variableChanged();
	load();
}

void DBRecords::setDirectionFilter( OptionsClass::FilterOptions f )
{
	// clear directions event flags with EventMask
	m_filterOptions = f | ( m_filterOptions & OptionsClass::EventMask );
	emit variableChanged();
	load();
}

/*
 * Reread the database, clearing out any existing cached records
 */
void DBRecords::load()
{
//	QTime t;
//	t.start();
	clear();

	if ( ! m_ldb->connectDB() )
		return;
//	qDebug( "ConnectDB(): %d ms", t.elapsed() );

	if ( ! m_ldb->setupQuery( m_filterOptions, m_maxRecords ) )
		return;
//	qDebug( "setupQuery(): %d ms", t.elapsed() );

	int id = 0;
	DBRecord * rec;
	while ( ( rec = m_ldb->getNextRecord() ) )
	{
		rec->setId( id );
		m_dbRecs << rec;
		emit contactRequested( id++ );
//		qDebug() << id << ": " << t.elapsed() << " ms";
	}
	m_ldb->disconnectDB();
	emit loaded();
}

void DBRecords::processContactRequest( const int id )
{
	if ( ! m_dbRecs.at( id )->contact()  )
	{
		if ( ! m_thread )
			loadContact( id );
		else
			m_threadQueue.enqueue( id );
	}
}
void DBRecords::nextInQueue()
{
	if ( ! m_threadQueue.isEmpty() )
	{
		int id = m_threadQueue.dequeue();
		bool found = false;
		for ( int i = 0; i < m_contactCache.size(); i++ )
		{
			QString name = m_contactCache.at( i )->name();
			if ( m_dbRecs.at( id )->name() == name )
			{
				m_dbRecs.at( id )->setContact( * m_dbRecs.at( m_contactCache.at( i )->id() )->contact( ) );
				found = true;
				break;
			}
		}

		if ( ! found )
			loadContact( id );
		else
		{
			loadAvatar( id );
			nextInQueue();
		}
	}
	else
	{
		delete m_thread;
		m_thread = 0;
	}
}

void DBRecords::updateContactCache( const int id )
{
	DBRecord * rec = m_dbRecs.at( id );
	CacheItem * item = new CacheItem( this );
	item->setId( rec->id() );
	QString str = rec->name();
	item->setName( str );
	m_contactCache.append( item );
}

void DBRecords::loadContact( const int id )
{
	const DBRecord * rec = m_dbRecs.at( id );
	if ( ( rec->name() != rec->phoneNumber() ) && ( ! rec->name().isEmpty() ) )
	{
		if ( ! m_thread )
		{
			m_thread = new ContactLoadThread( this );
			connect( m_thread, SIGNAL( finished() ), this, SLOT( threadFinished() ) );
		}
		m_thread->setDbRecord( rec );
		m_thread->start();
	}
	else
	{
		nextInQueue();
	}
}

void DBRecords::threadFinished()
{
	if ( m_thread->contact() )
	{
		const DBRecord * rec = m_thread->dbRecord();
		m_dbRecs.at( rec->id() )->setContact( * m_thread->contact() );
		updateContactCache( rec->id() );
		loadAvatar( rec->id() );
	}
	nextInQueue();
}

void DBRecords::loadAvatar( const int id )
{
	DBRecord * rec = m_dbRecs.at( id );
	qDebug() << "Loading avatar for " << rec->name();
	if ( ( rec->name() != rec->phoneNumber() ) && ( ! rec->name().isEmpty() ) )
	{
		if ( rec->contact() )
		{
			QList< QContactThumbnail > cthumbs = rec->contact()->details< QContactThumbnail >();
			if ( ! cthumbs.isEmpty() && ! cthumbs.first().thumbnail().isNull() )
			{
				rec->setAvatar( QIcon( QPixmap::fromImage( cthumbs.first().thumbnail() ) ) );
				emit avatarLoaded( id );
			}
		}
	}
}
